import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Meeting extends Event implements Observer
{
	protected CyclicBarrier barrier = null;
	private Time endOfMeetingTime = null;
	private final TimeDuration duration;
	private final String name;

	public Meeting(Time eventTime, List<Employee> members,
		TimeDuration lengthOfMeeting, final String name)
	{
		super(eventTime, members);
		priority = 3;
		this.duration = lengthOfMeeting;
		this.name = name;
		final Schedule schedule = members.get(0).getSchedule();
		barrier = new CyclicBarrier(members.size(), new Runnable()
		{
			public void run()
			{
				onMeetingStarted();
				getMembers().get(0).getSchedule()
					.notifyMeIn(duration, Meeting.this);
				synchronized (schedule)
				{
					String message = (schedule.getCurrentTime().toString()
						+ " " + name + " started");
					PrintBuffer.printMessage(schedule.getCurrentTime(), message);
				}

				synchronized (Meeting.this)
				{
					try
					{
						Meeting.this.wait();
					}
					catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				}
				String message = (endOfMeetingTime.toString() + " " + name
					+ " ended");
				PrintBuffer.printMessage(schedule.getCurrentTime(), message);
				onMeetingFinished();
			}
		});
	}

	public void run()
	{
		Employee employee = (Employee) Thread.currentThread();
		
		//Check that all members are still at the office
		for(Employee e : members){
			if(e.leftOffice()){
				//If someone already left the office
				//return without printing anything
				return;
			}
		}
		
		if(this instanceof Question){
			if(employee instanceof Manager){
				if(barrier.getNumberWaiting() + 1 != barrier.getParties()){
					throw new RuntimeException();
				}
			}
//			}else if(employee instanceof TeamLead){
//				if(barrier.getNumberWaiting() ){
//					throw new RuntimeException();
//				}
//			}
		}

		onEmployeeStartedMeeting(employee);
		
		try
		{
			barrier.await();
		}
		catch (InterruptedException e)
		{
			//e.printStackTrace();
		}
		catch (BrokenBarrierException e)
		{
			throw new RuntimeException(e);
		}

		onEmployeeFinishedMeeting(employee);
	}

	/**
	 * Empty method for default meetings
	 * @param employee
	 */
	protected void onEmployeeFinishedMeeting(Employee employee)
	{

	}
	
	/**
	 * Empty method for default meetings
	 * @param employee
	 */
	protected void onEmployeeStartedMeeting(Employee employee)
	{

	}

	/**
	 * Empty method for default meetings
	 */
	protected void onMeetingFinished()
	{

	}

	/**
	 * Empty method for default meetings
	 */
	protected void onMeetingStarted()
	{

	}

	@Override
	public String toString()
	{
		return "got to " + name;
	}

	@Override
	synchronized public void update(Observable o, Object arg)
	{
		endOfMeetingTime = (Time) arg;
		notify();
	}

}
